
#include "MyParser.h"
#include <assert.h>
#include <sstream>

MyParser* MyParser::_myParser=NULL;

MyParser::MyParser(void){
	
	//由於switch無法直接處理字串，因此我利用了map加以處理
	primaryType["arith"]=TYPE_ARITH;
	primaryType["("]=TYPE_LPARENT;
	primaryType["-"]=TYPE_NEGATIVE;
	primaryType["int"]=TYPE_INT;
	primaryType["double"]=TYPE_DOUBLE;
	primaryType["id"]=TYPE_ID;

}

MyParser::~MyParser(void){

}

MyParser* MyParser::getInstance(){

	if(_myParser==NULL){
		_myParser=new MyParser();
	}
	return _myParser;

}

std::string MyParser::isSyntax(std::queue<MyWord*>* tokens){
	
	_result="TRUE";
	_tokens=tokens;
	_root=expression();

	return _result;
}

MyWord* MyParser::arith_list(){
	
	if(_result!="TRUE")
		return NULL;

	//ARITH(expr_list)
	if(!_tokens->empty()){

		MyWord* current=_tokens->front();
		match("arith");
		match("(");
		std::vector<MyWord*>* temp=expr_list();
		if(temp==NULL)
			return NULL;
		current->_childs=temp;
		std::string opr=current->_value_string;
		//這裡是為了檢查目前的arith內部的數目，arith及內部的數目都寫在Myword.cpp中
		for(int i=0;i<MyWord::arithNumber;i++){
			//SUM在primary中就應該符合>=1的規則，因此如果在這看到就直接break
			if(opr=="SUM")
				break;
			if(MyWord::ariths[i]==opr){
				if(current->_childs->size()!=MyWord::ariths_num[i]){
					syntax_error();
					return NULL;
				}
			}
		}
		match(")");
		return current;
	}
	return NULL;
}

//處理a,b,c,....
std::vector<MyWord*>* MyParser::expr_list(){
	
	if(_result!="TRUE")
		return NULL;

	//expr_list=expression{,expression}
	std::vector<MyWord*>* childs=new std::vector<MyWord*>;
	MyWord* temp=expression();
	if(temp==NULL)
		return NULL;
	childs->push_back(temp);

	if(!_tokens->empty()){
		std::string next_token=_tokens->front()->_type;
		while(next_token==","){
			match(",");
			temp=expression();
			if(temp==NULL)
				return NULL;
			childs->push_back(temp);
			if(_tokens->empty())
				break;
			next_token=_tokens->front()->_type;
		}
	}
	return childs;

}

MyWord* MyParser::expression(){
	
	if(_result!="TRUE")
		return NULL;
	
	//expression=factor{add_op factor}
	MyWord* current=factor();
	if(!_tokens->empty()){
		std::string next_token=_tokens->front()->_type;
		while(next_token=="+"||next_token=="-"){
			MyWord* arith=add_op();
			arith->_childs=new std::vector<MyWord*>();
			arith->_childs->push_back(current);
			arith->_childs->push_back(factor());
			current=arith;
			if(_tokens->empty())
				break;
			next_token=_tokens->front()->_type;
		}
	}
	return current;
}

MyWord* MyParser::factor(){

	//factor=primary{mul_op primary}
	if(_result!="TRUE")
		return NULL;

	MyWord* current=primary();
	if(!_tokens->empty()){
		std::string next_token=_tokens->front()->_type;
		while(next_token=="*"||next_token=="/"){
			MyWord* arith=mul_op();
			arith->_childs=new std::vector<MyWord*>();
			arith->_childs->push_back(current);
			arith->_childs->push_back(primary());
			current=arith;
			if(_tokens->empty())
				break;
			next_token=_tokens->front()->_type;
		}
	}
	return current;
}

MyWord* MyParser::primary(){

// 	primary=	-expression
//				(expression)
// 				arith(expr_list)
// 				ID
// 				int
// 				double

	if(_result!="TRUE")
		return NULL;

	if(_tokens->empty()){
		syntax_error();
		return NULL;
	}

	MyWord* current=_tokens->front();

	switch(primaryType[current->_type]){

		case TYPE_ARITH:
			current=arith_list();
			break;

		case TYPE_LPARENT:
			match("(");
			current=expression();
			match(")");
			break;

		case TYPE_NEGATIVE:
			match("-");
			current=new MyWord("arith","NEGATIVE");
			current->_childs=new std::vector<MyWord*>();
			current->_childs->push_back(expression());
			break;

		case TYPE_INT:
		case TYPE_DOUBLE:
		case TYPE_ID:
			match(current->_type);
			break;

		default:
			syntax_error(current->_type);
			return NULL;
	}
	return current;
}

MyWord* MyParser::add_op(){
	
	std::string next_token=_tokens->front()->_type;
	if(next_token=="+"){
		match(next_token);
		return new MyWord("arith","ADD");
	}
	else if(next_token=="-"){
		match(next_token);
		return new MyWord("arith","SUB");
	}
	else{
		syntax_error(next_token);
	}
	return NULL;

}

MyWord* MyParser::mul_op(){
	
	std::string next_token=_tokens->front()->_type;
	if(next_token=="*"){
		match(next_token);
		return new MyWord("arith","MUL");
	}
	else if(next_token=="/"){
		match(next_token);
		return new MyWord("arith","DIV");
	}
	else{
		syntax_error(next_token);
	}
	return NULL;

}

void MyParser::match(std::string token){

	assert(!_tokens->empty());
	
	std::string next_token=_tokens->front()->_type;
	if(next_token==token){
		MyWord* temp=_tokens->front();
		_tokens->pop();
		//將之後不會用到或是會被取代的MyWord清除
		switch(primaryType[temp->_type]){
			case TYPE_ARITH: case TYPE_DOUBLE: case TYPE_ID: case TYPE_INT:
				break;
			default:
				delete temp;
				break;
		}
	}
	else{
		syntax_error(next_token);
	}

}

void MyParser::syntax_error(std::string token){
	
	_result="syntax error on token "+token;
}

void MyParser::syntax_error(){
	
	_result="syntax error";
}
MyWord* MyParser::getRoot(){
	
	assert(this->_root);
	return this->_root;
}
